#pragma once
#include<iostream>
using namespace std;

//枚举
enum Colour
{
	RED,
	BLACK
}; 

template<class K, class V>
struct RBTreeNode
{
	RBTreeNode<K, V>* _left;
	RBTreeNode<K, V>* _right;
	RBTreeNode<K, V>* _parent;
	pair<K, V> _kv;//key和val
	Colour _col;

	
//构造函数
	RBTreeNode(const pair<K, V>& kv)
		:_left(nullptr)
		, _right(nullptr)
		, _parent(nullptr)
		, _kv(kv)
		,_col(RED)
	{}
};

template<class K, class V>
class RBTree
{
	typedef RBTreeNode<K, V> Node;
public:
	bool Insert(const pair<K, V>& kv)
	{
		if (_root == nullptr)
		{
			_root = new Node(kv);
			_root->_col = BLACK;
			return true;
		}
		Node* parent = nullptr;
		Node* cur = _root;

		while (cur)
		{
			if (cur->_kv.first < kv.first)
			{
				parent = cur;
				cur = cur->_right;
			}
			else if (cur->_kv.first > kv.first)
			{
				parent = cur;
				cur = cur->_left;
			}
			else
			{
				return false;
			}
		}//找到空位置了
		//开始插入
		cur = new Node(kv);
		cur->_col = RED;//新增结点，选择新增红色的
		if (parent->_kv.first < kv.first)
		{
			parent->_right = cur;
			cur->_parent = parent;
		}
		else
		{
			parent->_left = cur;
			cur->_parent = parent;
		}
		//红黑树更新
		//1.新增结点的父亲是黑色的，不需要处理
		//2.新增结点的父亲是红色的，(变色,向上处理)OR(旋转+变色，向上处理)

		while (parent && parent->_col == RED)//父亲存在且红色
		{
			//	  g
			//	p	u
			//c
			//找叔叔
			Node* grandfather = parent->_parent;//一定有g
							//p是红色不是根
			if (parent == grandfather->_left)
			{
				//	  g
				//	p	u
				//c
				Node* uncle = grandfather->_right;
				//情况一: cur为红，p为红，g为黑，u存在且为红
				// 解决方式：将p, u改为黑，g改为红，然后把g当成cur，继续向上调整。
				if (uncle && uncle->_col == RED)//叔叔u存在且红色
				{

					//变色
					parent->_col = uncle->_col = BLACK;
					grandfather->_col = RED;

					//继续往上更新
					//不在此处判断是否为根
					cur = grandfather;
					parent = cur->_parent;
				}
				//	  g
				//	p	u
				//c
				//情况二: cur为红，p为红，g为黑，u不存在/u存在且为黑
				//解决方式:p为g的左孩子，cur为p的左孩子，则进行右单旋转；相反，
				//p为g的右孩子，cur为p的右孩子，则进行左单旋转
				//p、g变色--p变黑，g变红
				else//叔叔不存在OR叔叔存在且为黑
				{	//1.插入结点在左边
					if (cur == parent->_left)
					{
						RotateR(grandfather);//右单旋爷爷g
						parent->_col = BLACK;
						grandfather->_col = RED;
					}
					//	   g
					//	p	  u
					//	  c
					//2.插入结点在右边
					else
					{
						//左右双旋
						RotateL(parent);
						RotateR(grandfather);
						cur->_col = BLACK;
						grandfather->_col = RED;
					}

					break;//此时子树根节点为黑，调整完毕
				}
			}
			else//parent == grandfather->_right
			{
				//	  g
				//	u	p
				//		  c
				Node* uncle = grandfather->_left;
				//情况一: cur为红，p为红，g为黑，u存在且为红
				if (uncle && uncle->_col == RED)//叔叔u存在且红色
				{

					//变色
					parent->_col = uncle->_col = BLACK;
					grandfather->_col = RED;

					//继续往上更新
					//不在此处判断是否为根
					cur = grandfather;
					parent = cur->_parent;
				}
				//情况二: cur为红，p为红，g为黑，u不存在/u存在且为黑
				else//叔叔不存在OR叔叔存在且为黑
				{	//1.插入结点在右边
					if (cur == parent->_right)
					{
						RotateL(grandfather);//左单旋爷爷g
						parent->_col = BLACK;
						grandfather->_col = RED;
					}
					//	   g
					//	u	  p
					//		c
					//2.插入结点在左边
					else
					{
						//右左双旋
						RotateR(parent);
						RotateL(grandfather);
						cur->_col = BLACK;
						grandfather->_col = RED;
					}

					break;//此时子树根节点为黑，调整完毕
				}
			}
		}
		//不管前面更新到哪，确定更新根是黑色
		_root->_col = BLACK;


		return true;
	}

	//左单旋
	void RotateL(Node* parent)
	{
		Node* subR = parent->_right;
		Node* subRL = subR->_left;

		parent->_right = subRL;//先改左右子树
		subR->_left = parent;

		Node* parentParent = parent->_parent;//记录父亲的父亲

		parent->_parent = subR;//更新parent
		if (subRL)//subRL可能为空
		{
			subRL->_parent = parent;
		}
		//更新subR的parent
		if (_root == parent)//根节点
		{
			_root = subR;
			subR->_parent = nullptr;
		}
		else
		{//不是根节点
			if (parentParent->_left == parent)
			{
				parentParent->_left = subR;
			}
			else
			{
				parentParent->_right = subR;
			}
			subR->_parent = parentParent;
		}

	}

	//右单旋
	void RotateR(Node* parent)
	{
		Node* subL = parent->_left;
		Node* subLR = subL->_right;

		parent->_left = subLR;
		subL->_right = parent;

		Node* parentParent = parent->_parent;

		parent->_parent = subL;
		if (subLR)
		{
			subLR->_parent = parent;
		}
		if (_root == parent)
		{
			_root = subL;
			subL->_parent = nullptr;
		}
		else
		{
			if (parentParent->_left == parent)
			{
				parentParent->_left = subL;
			}
			else
			{
				parentParent->_right = subL;
			}
			subL->_parent = parentParent;
		}

	}

	//查找
	Node* Find(const K& key)
	{
		Node* cur = _root;
		while (cur)
		{
			if (cur->_kv.first < key)
			{
				cur = cur->_right;
			}
			else if (cur->_kv.first > key)
			{
				cur = cur->_left;
			}
			else
			{
				return cur;
			}
		}
	}

	//中序遍历
	void InOrder()
	{
		_InOrder(_root);
		cout << endl;
	}
	
	//是否平衡
	bool IsBalance()
	{
		return _IsBalance(_root);
	}

	//高度
	int Height()
	{
		return _Height(_root);
	}
private:
	//中序(套上一层调用_root)
	void _InOrder(Node* root)
	{
		if (root == nullptr)
		{
			return;
		}
		_InOrder(root->_left);
		cout << root->_kv.first << ":" << root->_kv.second << endl;
		_InOrder(root->_right);
	}

	//不能有连续红结点	//根节点到当前结点路径中黑色结点数量
	bool Check(Node* root, int blacknum, const int refVal)
	{
		if (root == nullptr)
		{
			//cout << blacknum << endl;//输出该路径黑色节点数量
			if (blacknum != refVal)
			{
				cout << "存在黑色结点数量不相等的路径" << endl;
				return false;
			}
			return true;
		}

		if (root->_col == RED&& root->_parent->_col==RED)
		{//反向检查，只用查父亲
			cout << "有连续的红色节点" << endl;
			return false;
		}
		if (root->_col == BLACK)
		{
			++blacknum;
		}
		return Check(root->_left, blacknum, refVal)
			&& Check(root->_right, blacknum, refVal);
	}
	//是否平衡
	bool _IsBalance(Node* root)
	{
		if (root == nullptr)
		{
			return true;
		}

		if (root->_col == RED)
		{
			return false;
		}

		//参考值
		int refVal = 0;
		Node* cur = root;
		while (cur)
		{
			if (cur->_col == BLACK)
			{
				refVal++;
			}
			cur = cur->_left;
		}
		int blacknum = 0;
		return Check(root, blacknum,refVal);
	}

	//高度
	int _Height(Node* root)
	{
		if (root == nullptr)
		{
			return 0;
		}
		int leftHeight = _Height(root->_left);
		int rightHeight = _Height(root->_right);

		return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
	}
private:
	Node* _root = nullptr;
};